HttpClient、OKhttp、RestTemplate接口调用对比,选择一个优秀的 HTTP Client 的重要性

您所在的位置:网站首页 springcloud dubbo选哪个好 HttpClient、OKhttp、RestTemplate接口调用对比,选择一个优秀的 HTTP Client 的重要性

HttpClient、OKhttp、RestTemplate接口调用对比,选择一个优秀的 HTTP Client 的重要性

2023-08-11 03:36| 来源: 网络整理| 查看: 265

选择一个优秀的 HTTP Client 的重要性 连接池请求/响应编解码(异步、超时设置等)API丰富程度及扩展性 JAVA 项目中接口调用怎么做 ? HttpClientOKhttpRestTemplate

上面是最常见的几种用法,我们基于目前主流的SpringBoot简单的介绍一下用法及对比。

基于springboot的HttpClient、OKhttp、RestTemplate对比 一、HttpClient

1、HttpClient 是Apache的一个三方网络框架,网络请求做了完善的封装,api众多,用起来比较方便,开发快。 Util工具类

package org.example; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.clienthods.CloseableHttpResponse; import org.apache.http.clienthods.HttpGet; import org.apache.http.clienthods.HttpPost; import org.apache.http.clienthods.HttpRequestBase; import org.apache.http.client.utils.URIBuilder; import org.apache.http.concurrent.FutureCallback; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; import org.apache.http.impl.nio.client.HttpAsyncClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import java.io.*; import java.net.URI; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; /** * @desc httpClient工具类 * @author liangliang * @date 2019/3/11 13:23 */ @Slf4j public class HttpClientUtil { /** * httpclient基础配置信息 */ private static final RequestConfig requestConfig = RequestConfig.custom() // 设置连接超时时间(单位毫秒) .setConnectTimeout(2000) // 设置请求超时时间(单位毫秒) .setConnectionRequestTimeout(2000) // socket读写超时时间(单位毫秒) .setSocketTimeout(1000) // 设置是否允许重定向(默认为true) .setRedirectsEnabled(true) //是否启用内容压缩,默认true .setContentCompressionEnabled(true) .build(); /** * 获得Http客户端 */ private static final CloseableHttpClient HTTP_CLIENT = HttpClientBuilder.create() .setRetryHandler(new DefaultHttpRequestRetryHandler()) //失败重试,默认3次 .build(); /** * 异步Http客户端 */ private static final CloseableHttpAsyncClient HTTP_ASYNC_CLIENT = HttpAsyncClients.custom() .setDefaultRequestConfig(requestConfig) .build(); /** * @desc 异步请求 * @param httpRequestBase * @author liangliang * @date 2019/3/11 13:23 */ private static void executeAsync(HttpRequestBase httpRequestBase) { HTTP_ASYNC_CLIENT.start(); HTTP_ASYNC_CLIENT.execute(httpRequestBase, new FutureCallback() { @SneakyThrows @Override public void completed(HttpResponse httpResponse) { log.info("thread id is : {}" ,Thread.currentThread().getId()); StringBuffer stringBuffer = new StringBuffer(); for (Header header : httpRequestBase.getAllHeaders()) { stringBuffer.append(header.toString()).append(","); } log.info("请求头信息: {}", stringBuffer.toString()); String responseResult = null; HttpEntity responseEntity = httpResponse.getEntity(); log.info("响应状态为:{}", httpResponse.getStatusLine()); if (responseEntity != null) { responseResult = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8); log.info("响应内容为:{}",responseResult); } stringBuffer = new StringBuffer(); for (Header header : httpResponse.getAllHeaders()) { stringBuffer.append(header.toString()).append(","); } log.info("响应头信息: {}", stringBuffer.toString())); } @Override public void failed(Exception e) { log.info("thread id is : {}",Thread.currentThread().getId()); log.error("Exception responseResult:{}", e); e.printStackTrace(); } @Override public void cancelled() { log.info(httpRequestBase.getRequestLine() + " cancelled"); } }); } /** * @desc String请求 * @param httpRequestBase * @return String * @author liangliang * @date 2019/3/11 13:23 */ private static String execute(HttpRequestBase httpRequestBase) { log.info("请求地址: {},请求类型: {}", httpRequestBase.getURI().toString(,httpRequestBase.getMethod())); StringBuffer stringBuffer = new StringBuffer(); for (Header header : httpRequestBase.getAllHeaders()) { stringBuffer.append(header.toString()).append(","); } log.info("请求头信息: {}", stringBuffer.toString()); log.info("请求参数: {}", httpRequestBase.getURI().getQuery()); String responseResult = null; // 响应模型 CloseableHttpResponse response = null; try { // 将上面的配置信息 运用到这个Get请求里 httpRequestBase.setConfig(requestConfig); long t1 = System.nanoTime();//请求发起的时间 response = HTTP_CLIENT.execute(httpRequestBase); // 从响应模型中获取响应实体 HttpEntity responseEntity = response.getEntity(); log.info("响应状态为:{}",response.getStatusLine()); long t2 = System.nanoTime();//收到响应的时间 if (responseEntity != null) { responseResult = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8); log.info("响应内容为:{}",responseResult); } stringBuffer = new StringBuffer(); for (Header header : response.getAllHeaders()) { stringBuffer.append(header.toString()).append(","); } log.info("响应头信息: {}", stringBuffer.toString()); log.info("执行时间: {}", (t2 - t1)); } catch (Exception e) { log.error("Exception responseResult:{}", e.getMassage()); e.printStackTrace(); } finally { try { if (response != null) { response.close(); } } catch (IOException e) { log.error("Exception responseResult:{}", e.getMassage()); e.printStackTrace(); } } return responseResult; } /** * @desc byte[]请求 * @param httpRequestBase * @return byte[] * @author liangliang * @date 2019/3/11 13:23 */ private static byte[] executeBytes(HttpRequestBase httpRequestBase) { log.info("请求地址: {},请求类型: {}", httpRequestBase.getURI().toString(,httpRequestBase.getMethod())); StringBuffer stringBuffer = new StringBuffer(); for (Header header : httpRequestBase.getAllHeaders()) { stringBuffer.append(header.toString()).append(","); } log.info("请求头信息: {}", stringBuffer.toString()); log.info("请求参数: {}", httpRequestBase.getURI().getQuery()); byte[] bytes = null; // 响应模型 CloseableHttpResponse response = null; try { // 将上面的配置信息 运用到这个Get请求里 httpRequestBase.setConfig(requestConfig); long t1 = System.nanoTime();//请求发起的时间 response = HTTP_CLIENT.execute(httpRequestBase); // 从响应模型中获取响应实体 HttpEntity responseEntity = response.getEntity(); log.info("响应状态为:{}", response.getStatusLine()); long t2 = System.nanoTime();//收到响应的时间 if (responseEntity != null) { bytes = EntityUtils.toByteArray(responseEntity); //判断是否需要解压,即服务器返回是否经过了gzip压缩--start Header responseHeader = response.getFirstHeader("Content-Encoding"); if (responseHeader != null && responseHeader.getValue().contains("gzip")) { GZIPInputStream gzipInputStream = null; ByteArrayOutputStream out = null; try { gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes)); out = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int offset = -1; while ((offset = gzipInputStream.read(buffer)) != -1) { out.write(buffer, 0, offset); } bytes = out.toByteArray(); } catch (IOException e) { log.error("Exception responseResult:{}", e.getMassage()); e.printStackTrace(); } finally { try { gzipInputStream.close(); out.close(); } catch (IOException e) { e.printStackTrace(); } } } //判断是否需要解压,即服务器返回是否经过了gzip压缩--end log.info("响应byte长度:{}", bytes.length); } stringBuffer = new StringBuffer(); for (Header header : response.getAllHeaders()) { stringBuffer.append(header.toString()).append(","); } log.info("响应头信息: {}", stringBuffer.toString()); log.info("执行时间: {}", (t2 - t1)); } catch (Exception e) { log.error("Exception responseResult:{}", e.getMassage()); e.printStackTrace(); } finally { try { if (response != null) { response.close(); } } catch (IOException e) { e.printStackTrace(); } } return bytes; } /** * @desc get请求 * @param url * @return tring * @author liangliang * @date 2019/3/11 13:23 */ public static String get(String url) { return get(url, new HashMap()); } /** * @desc get请求 * @param url, params * @return tring * @author mal * @date 2019/3/11 13:23 */ public static String get(String url, Map params) { HttpGet httpGet = null; List list = new ArrayList(); for (String key : params.keySet()) { list.add(new BasicNameValuePair(key, params.get(key).toString())); } // 由客户端执行(发送)Get请求 try { URI uri = new URIBuilder(url).addParameters(list).build(); // 创建Get请求 httpGet = new HttpGet(uri); } catch (Exception e) { log.error("Exception responseResult:{}", e.getMassage()); e.printStackTrace(); } return execute(httpGet); } /** * @desc get请求 * @param url, params * @return byte[] * @author liangliang * @date 2019/3/11 13:23 */ public static byte[] getBytes(String url, Map params) { HttpGet httpGet = null; List list = new ArrayList(); for (String key : params.keySet()) { list.add(new BasicNameValuePair(key, params.get(key).toString())); } // 由客户端执行(发送)Get请求 try { URI uri = new URIBuilder(url).addParameters(list).build(); // 创建Get请求 httpGet = new HttpGet(uri); } catch (Exception e) { log.error("Exception responseResult:{}", e.getMassage()); e.printStackTrace(); } return executeBytes(httpGet); } /** * @desc post请求 * @param url * @return String * @author liangliang * @date 2019/3/11 13:23 */ public static String post(String url) { return post(url, new HashMap()); } /** * @desc post请求 * @param url, params * @return String * @author liangliang * @date 2019/3/11 13:23 */ public static String post(String url, Map params) { HttpPost httpPost = null; List list = new ArrayList(); for (String key : params.keySet()) { list.add(new BasicNameValuePair(key, params.get(key).toString())); } try { URI uri = new URIBuilder(url).addParameters(list).build(); httpPost = new HttpPost(uri); } catch (Exception e) { log.error("Exception responseResult:{}", e.getMassage()); e.printStackTrace(); } return execute(httpPost); } /** * @desc post请求 * @param url, params * @return byte[] * @author liangliang * @date 2019/3/11 13:23 */ public static byte[] postBytes(String url, Map params) { HttpPost httpPost = null; List list = new ArrayList(); for (String key : params.keySet()) { list.add(new BasicNameValuePair(key, params.get(key).toString())); } try { URI uri = new URIBuilder(url).addParameters(list).build(); httpPost = new HttpPost(uri); } catch (Exception e) { log.error("Exception responseResult:{}", e.getMassage()); e.printStackTrace(); } return executeBytes(httpPost); } /** * @desc post请求 * @param url, json * @return String * @author liangliang * @date 2019/3/11 13:23 */ public static String postJson(String url, String json) { return postJson(url, json, false); } /** * @desc post请求 * @param url, json, gzip * @return String * @author liangliang * @date 2019/3/11 13:23 */ public static String postJson(String url, String json, boolean gzip) { HttpPost httpPost = null; try { URI uri = new URIBuilder(url).build(); httpPost = new HttpPost(uri); // post请求是将参数放在请求体里面传过去的,这里将entity放入post请求体中 httpPost.setHeader("Content-Type", "application/json;charset=utf8"); if (gzip) { httpPost.setHeader("Content-Encoding", "gzip"); ByteArrayOutputStream originalContent = new ByteArrayOutputStream(); originalContent.write(json.getBytes(StandardCharsets.UTF_8)); ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStream gzipOut = new GZIPOutputStream(baos); originalContent.writeTo(gzipOut); gzipOut.finish(); httpPost.setEntity(new ByteArrayEntity(baos .toByteArray(), ContentType.create("text/plain", "utf-8"))); } else { StringEntity entity = new StringEntity(json, "UTF-8"); httpPost.setEntity(entity); } } catch (Exception e) { log.error("Exception responseResult:{}", e.getMassage()); e.printStackTrace(); } return execute(httpPost); } /** * @desc post请求byte流 * @param url, bytes * @return String * @author liangliang * @date 2019/3/11 13:23 */ public static String postInputBytes(String url, byte[] bytes) { return postInputBytes(url, bytes, false); } /** * @desc post请求byte流 * @param url, bytes, gzip * @return String * @author liangliang * @date 2019/3/11 13:23 */ public static String postInputBytes(String url, byte[] bytes, boolean gzip) { HttpPost httpPost = null; try { URI uri = new URIBuilder(url).build(); httpPost = new HttpPost(uri); // post请求是将参数放在请求体里面传过去的,这里将entity放入post请求体中 if (gzip) { httpPost.setHeader("Content-Encoding", "gzip"); ByteArrayOutputStream originalContent = new ByteArrayOutputStream(); originalContent.write(bytes); ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStream gzipOut = new GZIPOutputStream(baos); originalContent.writeTo(gzipOut); gzipOut.finish(); httpPost.setEntity(new ByteArrayEntity(baos .toByteArray(), ContentType.create("text/plain", "utf-8"))); } else { ByteArrayEntity entity = new ByteArrayEntity(bytes, ContentType.create("text/plain", "utf-8")); httpPost.setEntity(entity); } } catch (Exception e) { log.error("Exception responseResult:{}", e.getMassage()); e.printStackTrace(); } return execute(httpPost); } /** * @desc post请求流 * @param url, is * @return String * @author liangliang * @date 2019/3/11 13:23 */ public static String postInputStream(String url, InputStream is) { return postInputStream(url, is, false); } /** * @desc post请求流 * @param url, is, gzip * @return String * @author liangliang * @date 2019/3/11 13:23 */ public static String postInputStream(String url, InputStream is, boolean gzip) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int ch; byte[] bytes = null; try { while ((ch = is.read(buffer)) != -1) { byteArrayOutputStream.write(buffer, 0, ch); } bytes = byteArrayOutputStream.toByteArray(); byteArrayOutputStream.close(); } catch (Exception e) { log.error("Exception responseResult:{}", e.getMassage()); e.printStackTrace(); } return postInputBytes(url, bytes, gzip); } /** * @desc post请求文件 * @param url, files * @return String * @author zhangh * @date 2019/3/11 13:23 */ public static String postFile(String url, File[] files) { return postFile(url, new HashMap(), files); } /** * @desc post请求文件 * @param url, params, files * @return String * @author zhangh * @date 2019/3/11 13:23 */ public static String postFile(String url, Map params, File[] files) { HttpPost httpPost = null; try { URI uri = new URIBuilder(url).build(); httpPost = new HttpPost(uri); MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create(); String filesKey = "files"; for (File file : files) { //multipartEntityBuilder.addPart(filesKey,new FileBody(file)); //与下面的语句作用相同 //multipartEntityBuilder.addBinaryBody(filesKey, file); // 防止服务端收到的文件名乱码。 我们这里可以先将文件名URLEncode,然后服务端拿到文件名时在URLDecode。就能避免乱码问题。 // 文件名其实是放在请求头的Content-Disposition里面进行传输的,如其值为form-data; name="files"; filename="头像.jpg" multipartEntityBuilder.addBinaryBody(filesKey, file, ContentType.DEFAULT_BINARY, URLEncoder.encode(file.getName(), "utf-8")); } // 其它参数(注:自定义contentType,设置UTF-8是为了防止服务端拿到的参数出现乱码) ContentType contentType = ContentType.create("text/plain", StandardCharsets.UTF_8); for (String key : params.keySet()) { multipartEntityBuilder.addTextBody(key, params.get(key).toString(), contentType); } HttpEntity entity = multipartEntityBuilder.build(); // post请求是将参数放在请求体里面传过去的,这里将entity放入post请求体中 httpPost.setEntity(entity); } catch (Exception e) { log.error("Exception responseResult:{}", e.getMassage()); e.printStackTrace(); } return execute(httpPost); } } 二、OKhttp

1、高效的HTTP客户端,它能允许同一ip和端口的请求重用一个socket,这种方式能大大降低网络连接的时间,和每次请求都建立socket,再断开socket的方式相比,降低了服务器服务器的压力,透明的GZIP压缩减少响应数据的大小;缓存响应内容。 2、okhttp 对http和https都有良好的支持。 3、okhttp 对大数据量的网络请求支持非常好。

Util工具类

import okhttp3.*; import org.apache.commons.lang3.exception.ExceptionUtils; import java.io.File; import java.util.Iterator; import java.util.Map; @Slf4j public class OkHttpUtil{ private static OkHttpClient okHttpClient; @Autowired public OkHttpUtil(OkHttpClient okHttpClient) { OkHttpUtil.okHttpClient= okHttpClient; } /** * get * @param url 请求的url * @param param 请求的参数 * @return */ public static String get(String url, Map param) { String responseBody = ""; StringBuffer sb = new StringBuffer(url); if (param!= null && param.keySet().size() > 0) { boolean firstFlag = true; Iterator iterator = param.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); if (firstFlag) { sb.append("?" + entry.getKey() + "=" + entry.getValue()); firstFlag = false; } else { sb.append("&" + entry.getKey() + "=" + entry.getValue()); } } } Request request = new Request.Builder() .url(sb.toString()) .build(); Response response = null; try { response = okHttpClient.newCall(request).execute(); int status = response.code(); if (response.isSuccessful()) { return response.body().string(); } } catch (Exception e) { log.error("okhttp3 post exception:{}", e.getMessage()); } finally { if (response != null) { response.close(); } } return responseBody; } /** * post * * @param url 请求的url * @param params post form 提交的参数 * @return */ public static String post(String url, Map params) { String responseBody = ""; FormBody.Builder builder = new FormBody.Builder(); //添加参数 if (params != null && params.keySet().size() > 0) { for (String key : params.keySet()) { builder.add(key, params.get(key)); } } Request request = new Request.Builder() .url(url) .post(builder.build()) .build(); Response response = null; try { response = okHttpClient.newCall(request).execute(); int status = response.code(); if (response.isSuccessful()) { return response.body().string(); } } catch (Exception e) { log.error("okhttp3 post exception:{}", e.getMessage()); } finally { if (response != null) { response.close(); } } return responseBody; } /** * get * @param url 请求的url * @param param 请求的参数 * @return */ public static String getForHeader(String url, Map param) { String responseBody = ""; StringBuffer sb = new StringBuffer(url); if (param != null && param.keySet().size() > 0) { boolean firstFlag = true; Iterator iterator = param.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); if (firstFlag) { sb.append("?" + entry.getKey() + "=" + entry.getValue()); firstFlag = false; } else { sb.append("&" + entry.getKey() + "=" + entry.getValue()); } } } Request request = new Request.Builder() .addHeader("key", "value") .url(sb.toString()) .build(); Response response = null; try { response = okHttpClient.newCall(request).execute(); int status = response.code(); if (response.isSuccessful()) { return response.body().string(); } } catch (Exception e) { log.error("okhttp3 post exception:{}", e.getMessage()); } finally { if (response != null) { response.close(); } } return responseBody; } /** * Post请求发送JSON数据 * @param url 请求Url * @param jsonParams 请求的JSON */ public static String postJsonParams(String url, String jsonParams) { String responseBody = ""; RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonParams); Request request = new Request.Builder() .url(url) .post(requestBody) .build(); Response response = null; try { response = okHttpClient.newCall(request).execute(); int status = response.code(); if (response.isSuccessful()) { return response.body().string(); } } catch (Exception e) { log.error("okhttp3 post exception:{}", e.getMessage()); } finally { if (response != null) { response.close(); } } return responseBody; } /** * Post请求发送xml类型数据 * @param url 请求Url * @param xml 请求的xml */ public static String postXmlParams(String url, String xml) { String responseBody = ""; RequestBody requestBody = RequestBody.create(MediaType.parse("application/xml; charset=utf-8"), xml); Request request = new Request.Builder() .url(url) .post(requestBody) .build(); Response response = null; try { response = okHttpClient.newCall(request).execute(); int status = response.code(); if (response.isSuccessful()) { return response.body().string(); } } catch (Exception e) { log.error("okhttp3 post exception:{}", e.getMessage()); } finally { if (response != null) { response.close(); } } return responseBody; } } 三、RestTemplate

1、Spring 提供的用于访问Rest服务的客户端, RestTemplate 提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。 2、面向对 RESTful Web 服务调用的功能。

在微服务中的使用

1、第三方服务调用,个人常用 RestTemplate, 这里RestTemplate未未进行封装,直接使用其方法。

2、微服务间调用,个人使用feign,同时使用OKhttp替换feign中默认的httpClient。 Feign在默认情况下使用的是JDK原生的URLConnection发送HTTP请求,没有连接池,但是对每个地址会保持一个长连接,即利用HTTP的persistence connection 。 我们可以用HTTP Client 或 OKhttp 替换Feign原始的http client, 从而获取连接池、超时时间等与性能息息相关的控制能力。

SpringCloud 1.x

org.apache.httpcomponents httpclient com.netflix.feign feign-httpclient ${feign-httpclient}

application.properties中添加:

feign.httpclient.enabled=true io.github.openfeign feign-okhttp 10.2.0

application.properties中添加:

feign.okhttp.enabled=true

SpringColud 2.x

com.squareup.okhttp3 okhttp 3.10.0

application.properties中添加:

feign.okhttp.enabled=true


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3